<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
import { Base } from '../threejs/base';
import * as THREE from 'three';
import fish from '../assets/fish.svg';
import snake from '../assets/snake.png';
import { gsap } from 'gsap';
class Demo extends Base {
  mesh;
  m;
  time;
  mouse;
  controls = { color: 0xff0000 };
  geometry = { Geometry: 1 };
  initGui() {
    const g = this.gui.addFolder('调整这里试试');
    let colorChange = g.addColor(this.controls, 'color').name('色值');
    colorChange.onChange((value) => {
      console.log(value);
      for (let i = 0; i < this.scene.children.length; i++) {
        // 方式1
        // this.scene.children[i].material.uniforms.uColor.value.set(value); // 改变颜色为绿色
        // 方式2
        var newColor = new THREE.Color(this.controls.color);
        // 更新材质的颜色
        console.log(newColor);
        this.scene.children[i].material.uniforms.uColor.value.copy(newColor); // 如果颜色是uniform
      }
    });
    g.open();
  }

  initShader() {
    this.mouse = new THREE.Vector2();
    this.raycaster = new THREE.Raycaster();
    this.camera.position.set(0, 0, 4);
    this.camera.lookAt(new THREE.Vector3());
    this.renderer.setClearColor(0x160016, 1);
    window.addEventListener('mousemove', (e) => {
      this.mouse.x = (e.clientX / window.innerWidth) * 2 - 1;
      this.mouse.y = (-e.clientY / window.innerHeight) * 2 + 1;
      // console.log(this.mouse)
    });
    this.ini01(
      `
      uniform float uTime;
      uniform float angle;
      uniform float progress;
      uniform vec4 resolution;
      varying vec2 vUv;
      varying float vFrontShadow;
      // varying float vBackShadow;
      // varying float vProgress;

      uniform sampler2D texture1;
      uniform sampler2D texture2;
      uniform vec2 pixels;

      const float pi = 3.1415925;

      mat4 rotationMatrix(vec3 axis, float angle) {
          axis = normalize(axis);
          float s = sin(angle);
          float c = cos(angle);
          float oc = 1.0 - c;
          
          return mat4(oc * axis.x * axis.x + c,           oc * axis.x * axis.y - axis.z * s,  oc * axis.z * axis.x + axis.y * s,  0.0,
                      oc * axis.x * axis.y + axis.z * s,  oc * axis.y * axis.y + c,           oc * axis.y * axis.z - axis.x * s,  0.0,
                      oc * axis.z * axis.x - axis.y * s,  oc * axis.y * axis.z + axis.x * s,  oc * axis.z * axis.z + c,           0.0,
                      0.0,                                0.0,                                0.0,                                1.0);
      }
      vec3 rotate(vec3 v, vec3 axis, float angle) {
        mat4 m = rotationMatrix(axis, angle);
        return (m * vec4(v, 1.0)).xyz;
      }
      void main() {
        vUv = uv;
        float pi = 3.14159265359;


        float finalAngle = angle - 0.*0.3*sin(progress*6.);

        // @todo account for aspect ratio!!!
        vec3 newposition = position;

        // float angle = pi/10.;
        float rad = 0.1;
        float rolls = 8.;
        // rot
        newposition = rotate(newposition - vec3(-.5,.5,0.), vec3(0.,0.,1.),-finalAngle) + vec3(-.5,.5,0.);

        float offs = (newposition.x + 0.5)/(sin(finalAngle) + cos(finalAngle)) ; // -0.5..0.5 -> 0..1
        float tProgress = clamp( (progress - offs*0.99)/0.01 , 0.,1.);

        // shadows
        vFrontShadow = clamp((progress - offs*0.95)/0.05,0.7,1.);
        // vBackShadow = 1. - clamp(abs((progress - offs*0.9)/0.1),0.,1.);
        // vProgress = clamp((progress - offs*0.95)/0.05,0.,1.);

        

        newposition.z =  rad + rad*(1. - offs/2.)*sin(-offs*rolls*pi - 0.5*pi);
        newposition.x =  - 0.5 + rad*(1. - offs/2.)*cos(-offs*rolls*pi + 0.5*pi);
        // // rot back
        newposition = rotate(newposition - vec3(-.5,.5,0.), vec3(0.,0.,1.),finalAngle) + vec3(-.5,.5,0.);
        // unroll
        newposition = rotate(newposition - vec3(-.5,0.5,rad), vec3(sin(finalAngle),cos(finalAngle),0.), -pi*progress*rolls);
        newposition +=  vec3(
          -.5 + progress*cos(finalAngle)*(sin(finalAngle) + cos(finalAngle)), 
          0.5 - progress*sin(finalAngle)*(sin(finalAngle) + cos(finalAngle)),
          rad*(1.-progress/2.)
        );

        // animation
        vec3 finalposition = mix(newposition,position,tProgress);
        gl_Position = projectionMatrix * modelViewMatrix * vec4(finalposition, 1.0 );
      }
    `,
      `
      uniform float uTime;
      uniform float progress;
      uniform sampler2D texture1;
      uniform sampler2D texture2;
      uniform vec4 resolution;

      varying vec2 vUv;
      varying float vFrontShadow;
      // varying float vBackShadow;
      // varying float vProgress;
      void main()	{
        vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
        gl_FragColor = texture2D(texture1,newUV);
        gl_FragColor.rgb *=vFrontShadow;
        gl_FragColor.a = clamp(progress*5.,0.,1.);
      }
    `,
      0,
      0
    );
  }

  ini01(vertexShader, fragmentShader, x, y) {
    const geometry = new THREE.PlaneGeometry(1, 1, 30, 30);
    let material = new THREE.ShaderMaterial({
      uniforms: {
        uTime: { value: 0 },
        uColor: { value: new THREE.Color(0xff0000) },
        texture1: {
          // value: new THREE.TextureLoader().load('../assets/snake.png'),
          value: new THREE.TextureLoader().load(snake),
        },
        texture2: {
          // value: new THREE.TextureLoader().load('../assets/snake.png'),
          value: new THREE.TextureLoader().load(snake),
        },
        angle: { value: 0.8 },
        resolution: { type: "v4", value: new THREE.Vector4() },
        progress: { value: 0 },
      },
      vertexShader,
      fragmentShader,
      side: THREE.DoubleSide,
      // transparent: true,
      // depthTest: false,
      // depthWrite: false,
      // wireframe: true,
    });
    // let texture = new THREE.Texture(o.image);
    // texture.needsUpdate = true;
    // // image cover
    // let imageAspect = o.iHeight / o.iWidth;
    // let a1;
    // let a2;
    // if (o.height / o.width > imageAspect) {
    //   a1 = (o.width / o.height) * imageAspect;
    //   a2 = 1;
    // } else {
    //   a1 = 1;
    //   a2 = o.height / o.width / imageAspect;
    // }

    material.uniforms.resolution.value.x = 500;
    material.uniforms.resolution.value.y = 500;
    material.uniforms.resolution.value.z = 1;
    material.uniforms.resolution.value.w = 1;
    
    const mesh = new THREE.Mesh(geometry, material);

    
    mesh.position.x = x;
    mesh.position.y = y;
    this.scene.add(mesh);
  }

  renderContent() {
    // this.time += 0.05;
    let time = this.clock.getElapsedTime();
    for (let i = 0; i < this.scene.children.length; i++) {
      this.scene.children[i].material.uniforms.progress.value = time;
      this.scene.children[i].rotation.y = time / 100;
    }
  }
}

let ins;
const dom = ref();
let run = () => {
  console.log(ins.scene.children[0].material.uniforms.vProgress);
  gsap.to(ins.scene.children[0].material.uniforms.vProgress, {
    value: 1,
    onComplete: () => {
      // animating = false;
      // geometry.attributes.position.array = geometryAttributes[current];
      // geometry.attributes.position.needsUpdate = true;
      // material.uniforms.uColor.value = color;
      // material.uniforms.uProgress.value = 0;
      // ins.scene.children[0].material.uniforms.vProgress.value=0
    },
  });
};
onMounted(() => {
  ins = new Demo().init(dom.value);
});
onUnmounted(() => {
  ins.dispose();
});

const text = `
本示例主要学习了通过 uniforms 向着色器传递数据。示例主要代码如下：
\`\`\`
const m = new THREE.ShaderMaterial({
  uniforms: {
    uColor: { value: new THREE.Color(0xff0000) }
  },
  vertexShader: \`
    void main() {
      
      // position 是顶点的local坐标(Model坐标)
      // Model坐标 * ModelMatrix = World坐标；World坐标 * ViewMatrix = Camera坐标；Camera坐标 * ProjectionMatrix = 投影坐标

      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }\`,
  fragmentShader: \`
    uniform vec3 uColor;  // 接收 uniforms 传过来的数据
    
    void main() {
      gl_FragColor = vec4(uColor, 1.0);
    }\`
});
\`\`\`
`;
</script>

<template>
  <div class="shader-box" ref="dom" @click="run"></div>
  <v-md-preview :text="text"></v-md-preview>
</template>

<style scoped></style>
